<?php
/**
 * Template instance.
 * <p>Currently, it's only able to render templates, not to build them
 * <p>Usage :</p>
 * <code>//read the template file :
 * $str=file_get_contents($file);
 * // build the template instance :
 * $tpl=new djangoTpl($str);
 * // Renders it with some data
 * echo $tpl->render($data);</code>
 * @uses dataPath
 * Django's templating engine (partial) PHP implementation
 * @link http://djangoproject.com Django
 * this file is from a webappkit package (kit)
 * @link http://webappkit.net
 * @package djtpl
 * @author J.Ducastel <nospam0@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */
class DjTplTemplate {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	/**
	* constructor alias
	* @access
	*/
	function DjTplTemplate(&$str) {
		$this->__construct($str);
	}/**/

	/**
	* "real" constructor
	* @access public
	* @param string $str
	*/
	function __construct(&$str) {
		$this->_buildFromString($str);
	}

	/**
	* returns a template from a file's content
	* @static
	* @param string $filename
	* @return djtplTemplate
	*/
	function & getFromFile($filename) {
		if (!file_exists($filename)) {
			$f=false;
			return $f;
		}
		$str=join('',file($filename));
		return new djtplTemplate($str);
	}
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
	/**
	* Render's template with some data, as a string
	* @param array $data
	* @access public
	* @return string
	*/
	function render($data=null) {
		// is the template extending another ?
		if ($this->parent) {
			//$rendered.='<p>extending '.$this->parent.'</p>';
			// searching parent within self storage
			if (!$this->storage
            or !$parent=$this->storage->get($this->parent)) {
				trigger_error("parent template not found ({$this->parent})");
				return false;
			}
			// overriding parent blocks with self blocks
			// echo '<pre>'; print_r($parent->blocks); exit;
			// echo '<pre>'; print_r($this); exit;
            // echo '<pre>'; print_r(array_keys($this->blocks)); exit;
			$parent->extend($this);
			// echo '<pre>'; print_r($context); exit;
			// rendering extended parent
			return $parent->render($data);
		} else {
			// building context
            if (is_a($data,'DjTplContext')) {
                $context=&$data;
            } else
                $context=&new DjTplContext($data);
			// rendering
			$rendered='';
			// looping nodes
			for ($n=0; $n<count($this->nodes); $n++) {
				$rendered.=$this->nodes[$n]->render($context);
			}
		}
		return $rendered;
	}

	/**
	 * extend a template by overriding self blocks with child blocks
	 * @access public
	 * @param DjTplTemplate $child
	 * @return bool
	 */
	function extend($child) {
		if (!is_a($child,'DjTplTemplate'))
			return false;
		// echo '<pre>'; print_r($child->blocks);// exit;
        /*foreach (array_keys($child->blocks) as $name) {
            $this->blocks[$name]=$child->blocks[$name];
            //$this->blocks[$name]->setTemplate($this);
        }*/
		foreach ($child->blocks as $name => $childBlock) {
			$block=&$this->blocks[$name];
			$block=$childBlock;
			// echo "<p>overriding block $name</p>";
		}
		return true;
	}

    /**
     * sets storage (which will be used for template inheritance)
     * @access public
     * @param DjTplStorage $storage
     * @return bool
     */
    function setStorage($storage) {
        if (!is_a($storage,'DjTplStorage'))
            return false;
        $this->storage=&$storage;
        return true;
    }


	/**
	* @var array djangoTplNode instances
	*/
	var $nodes=array();

	/**
	 * @var string parent template name if relevant
	 */
	var $parent;

    /**
     * @var DjTplStorage reference to template storage, which may be used for inheritance
     */
    var $storage;

	/**
	 * @var array references to named block nodes name => node
	 */
	var $blocks=array();
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
	/**
	* builds internal tree from string
	* @param string $str
	* @access private
	* @uses DjTplParser
	* @return bool
	*/
	function _buildFromString(&$str) {
		// spliting into tokens
		$tokens=djtplParser::tokenize($str);
		//echo '<pre>'; print_r($tokens);
		while ($node=&DjTplParser::tokensToNode($tokens)) {
			// searching for 'extends' node
			if ($node->isTag('extends')) {
				$this->parent=$node->parent;
			} else if ($node->isTag('include')) {
				// echo '<pre>'; print_r($node);
			}
			// indexing blocks
			else if ($node->isTag('block') and $block=$node->isBlock()) {
				// echo "<p>block $block</p>";
				$this->blocks[$block]=&$node;
			}
			//echo '<pre>'; print_r($node);
			// adding node to tree
			$this->nodes[]=&$node;
		}
		return true;
	}/**/
}
